package com.alipay.rebate.shop.exceptoin;

import com.alipay.rebate.shop.constants.StatusCode;
import com.alipay.rebate.shop.constants.StatusCodeMapper;
import com.alipay.rebate.shop.pojo.common.ResponseResult;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class ProjectExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger(ProjectExceptionHandler.class);

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResponseResult<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        StringBuilder errorInfo = new StringBuilder();
        BindingResult bindingResult = ex.getBindingResult();
        for(int i = 0; i < bindingResult.getFieldErrors().size(); i++){
            if(i > 0){
                errorInfo.append(",");
            }
            FieldError fieldError = bindingResult.getFieldErrors().get(i);
            errorInfo.append(fieldError.getField()).append(" :").append(fieldError.getDefaultMessage());
        }

        //返回BaseResponse
        ResponseResult<String> responseResult = new ResponseResult<>();
        responseResult.setMsg(errorInfo.toString());
        responseResult.setStatus(StatusCode.PARAMETER_CHECK_ERROR.getCode());
        responseResult.setTime(System.currentTimeMillis());
        return responseResult;
    }


    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResponseResult<String> handleConstraintViolationException(ConstraintViolationException ex) {
        StringBuilder errorInfo = new StringBuilder();
        String errorMessage ;

        Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
        for (ConstraintViolation<?> item : violations) {
            errorInfo.append(item.getMessage()).append(",");
        }
        errorMessage = errorInfo.toString().substring(0, errorInfo.toString().length()-1);

        //返回BaseResponse
        ResponseResult<String> responseResult = new ResponseResult<>();
        responseResult.setMsg(errorMessage);
        responseResult.setStatus(StatusCode.PARAMETER_CHECK_ERROR.getCode());
        responseResult.setTime(System.currentTimeMillis());
        return responseResult;
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResponseResult<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {

        ResponseResult<String> responseResult = new ResponseResult<>();
        responseResult.setMsg("请求body不能为空: " + ex.getMessage());
        responseResult.setStatus(StatusCode.PARAMETER_CHECK_ERROR.getCode());
        responseResult.setTime(System.currentTimeMillis());

        return responseResult;
    }

    @ExceptionHandler(RedisConnectionFailureException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResponseResult<String> handleRedisConnectionException(RedisConnectionFailureException ex) {

        logger.error("redis connect error : {}", ex.getMessage());
        ResponseResult<String> responseResult = new ResponseResult<>();
        responseResult.setMsg(StatusCodeMapper.getMsg(StatusCode.REDIS_CONNECT_FAIL.getCode()));
        responseResult.setStatus(StatusCode.REDIS_CONNECT_FAIL.getCode());
        responseResult.setTime(System.currentTimeMillis());

        return responseResult;
    }

    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseResult<Object> handleBusinessException(BusinessException ex) {

        logger.error("Business Exception : {}", ex);
        ResponseResult<Object> responseResult = new ResponseResult<>();
        responseResult.setMsg(ex.getMessage());
        if(ex.getMessage() == null){
            responseResult.setMsg(StatusCodeMapper.getMsg(ex.getStatusCode().getCode()));
        }
        responseResult.setStatus(ex.getStatusCode().getCode());
        responseResult.setTime(System.currentTimeMillis());
        if(ex instanceof TaobaoAuthMultiException){
            responseResult.setData((((TaobaoAuthMultiException) ex).getObj()));
        }
        return responseResult;
    }

    @ExceptionHandler(IncorrectCredentialsException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseResult<String> handleIncorrectCredentialsException(IncorrectCredentialsException ex) {

        logger.error("IncorrectCredentialsException Exception : {}", ex.getMessage());
        ResponseResult<String> responseResult = new ResponseResult<>();
        responseResult.setMsg(StatusCodeMapper.getMsg(StatusCode.USER_PASSWORD_NOT_RIGHT.getCode()));
        responseResult.setStatus(StatusCode.USER_PASSWORD_NOT_RIGHT.getCode());
        responseResult.setTime(System.currentTimeMillis());

        return responseResult;
    }


    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseResult<Object> handleDefaultException(Exception ex) {

        if (ex instanceof BusinessException){
            return handleBusinessException((BusinessException) ex);
        }
        if (ex.getCause() instanceof BusinessException){
            return handleBusinessException((BusinessException) ex.getCause());
        }
        logger.debug("unknow exception is: {}" , ex);
        ResponseResult<Object> responseResult = new ResponseResult<>();
        responseResult.setMsg(ex.getMessage());
        responseResult.setStatus(StatusCode.INTERNAL_ERROR.getCode());
        responseResult.setTime(System.currentTimeMillis());
        return responseResult;
    }

}
